/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>

#include "yaffut.h"
#include "myassert.h"
#include "TestEventServer.h"

#include "Commands.h"
#include "TestSession.h"
#include "color.h"
#include "Global.h"
#include "CommServer.h"

using namespace std;
using namespace Chronos;

struct CommCommandTest : public CommCommand {
	CommCommandTest() : session1("player1") {}

    TestSession session1;
};

TEST(CommCommandTest, testCommCommand) {
    execute(session1);
    session1.SESSION_CHECKWRITTEN("Usage: comm [list|join|leave|show|create]\n");
}


struct CommListCommandTest : public CommListCommand {
	CommListCommandTest() : session1("player1"), commServer(eventServer)
    {
        Global<CommServer>::set(&commServer);
    }

    TestSession session1;
    TestEventServer eventServer;
    CommServer commServer;
};


TEST(CommListCommandTest, testCommListCommandNotMember) {
  	execute(session1);
    session1.SESSION_CHECKWRITTEN("Channels:\n");
    
	commServer.addChannel("channel1", ANSI_BLUE);
	commServer.addChannel("channel2", ANSI_RED);
  	execute(session1);
    session1.SESSION_CHECKWRITTEN("Channels:\n   channel1\n   channel2\n");
}


TEST(CommListCommandTest, testCommListCommandWithMember) {
	commServer.addChannel("channel1", ANSI_BLUE);
	commServer.addChannel("channel2", ANSI_RED);
    commServer.join(session1, "channel1");
    session1.clear();

  	execute(session1);
    session1.SESSION_CHECKWRITTEN("Channels:\n   channel1 *\n   channel2\n");
}


TEST(CommListCommandTest, testCommListShowPlayerChannel) {
	commServer.addChannel("c1", ANSI_BLUE);
	commServer.addPlayerChannel(session1, "custom", ANSI_BLUE);
    commServer.join(session1, "c1");
    session1.clear();

    execute(session1);
    session1.SESSION_CHECKWRITTEN("Channels:\n   c1 *\n   custom P *\n");
}


struct CommShowCommandTest : public CommShowCommand {
	CommShowCommandTest() : session1("player1"), session2("player2"), commServer(eventServer)
    {
        Global<CommServer>::set(&commServer);
    }

    TestSession session1;
    TestSession session2;
    TestEventServer eventServer;
    CommServer commServer;
};


TEST(CommShowCommandTest, testShouldShowAllMembers) {
	commServer.addChannel("channel1", ANSI_BLUE);
    commServer.join(session1, "channel1");
    session1.clear();

  	execute(session1, "channel1");
    session1.SESSION_CHECKWRITTEN("["ANSI_BLUE"channel1"ANSI_NORMAL"] members: player1\n");

    commServer.join(session2, "channel1");
    session1.clear();
  	execute(session1, "channel1");
    session1.SESSION_CHECKWRITTEN("["ANSI_BLUE"channel1"ANSI_NORMAL"] members: player1, player2\n");
}


struct CommCreateCommandTest : public CommCreateCommand {
	CommCreateCommandTest() : session1("player1"), session2("player2"), commServer(eventServer)
    {
        Global<CommServer>::set(&commServer);
    }

    TestSession session1;
    TestSession session2;
    TestEventServer eventServer;
    CommServer commServer;
};


TEST(CommCreateCommandTest, testShouldNotCreateExistingChannel) {
    commServer.addChannel("existing", ANSI_BLUE);
    commServer.addPlayerChannel(session1, "existing", ANSI_BLUE);
    session1.SESSION_CHECKWRITTEN("Channel ["ANSI_BLUE"existing"ANSI_NORMAL"] already exists.\n");
}


TEST(CommCreateCommandTest, testShouldCreateChannel) {
    commServer.addPlayerChannel(session1, "mychannel", ANSI_BLUE);
    session1.SESSION_CHECKWRITTEN("Channel ["ANSI_BLUE"mychannel"ANSI_NORMAL"] created.\n"
            "You joined the ["ANSI_BLUE"mychannel"ANSI_NORMAL"] channel.\n");
}


TEST(CommCreateCommandTest, testShouldDeleteChannelAfterPlayerLeaves) {
    commServer.addPlayerChannel(session1, "mychannel", ANSI_BLUE);
    session1.clear();

    commServer.notify(Event::PLAYER_LOGOUT, session1);
    session1.SESSION_CHECKWRITTEN("You left the ["ANSI_BLUE"mychannel"ANSI_NORMAL"] channel.\n"
            "Channel ["ANSI_BLUE"mychannel"ANSI_NORMAL"] destroyed.\n");

    commServer.addChannel("mychannel", ANSI_BLUE);
}


TEST(CommCreateCommandTest, testShouldDeleteChannelAfterAllPlayersLeave) {
    commServer.addPlayerChannel(session1, "mychannel", ANSI_BLUE);
    session1.clear();

    commServer.join(session2, "mychannel");
    session1.SESSION_CHECKWRITTEN(ANSI_BLUE"[mychannel] player2 joins the channel."ANSI_NORMAL"\n");
    session2.SESSION_CHECKWRITTEN("You joined the ["ANSI_BLUE"mychannel"ANSI_NORMAL"] channel.\n");

    commServer.notify(Event::PLAYER_LOGOUT, session1);
    session1.SESSION_CHECKWRITTEN("You left the ["ANSI_BLUE"mychannel"ANSI_NORMAL"] channel.\n");
    session2.clear();
    
    commServer.notify(Event::PLAYER_LOGOUT, session2);
    session2.SESSION_CHECKWRITTEN("You left the ["ANSI_BLUE"mychannel"ANSI_NORMAL"] channel.\n"
            "Channel ["ANSI_BLUE"mychannel"ANSI_NORMAL"] destroyed.\n");
}


struct CommLeaveCommandTest : public CommLeaveCommand {
	CommLeaveCommandTest() : session1("player1"), commServer(eventServer)
    {
        Global<CommServer>::set(&commServer);
        commServer.addPlayerChannel(session1, "mychannel", ANSI_BLUE);
        session1.clear();
    }

    TestSession session1;
    TestEventServer eventServer;
    CommServer commServer;
};


TEST(CommLeaveCommandTest, testShouldDeletePlayerChannelAfterPlayerLeaves) {
    execute(session1, "mychannel");
    session1.SESSION_CHECKWRITTEN("You left the ["ANSI_BLUE"mychannel"ANSI_NORMAL"] channel.\n"
            "Channel ["ANSI_BLUE"mychannel"ANSI_NORMAL"] destroyed.\n");
}

